home *** CD-ROM | disk | FTP | other *** search
/ Tech Arsenal 1 / Tech Arsenal (Arsenal Computer).ISO / tek-13 / dte5_1.zip / HWIND.C < prev    next >
C/C++ Source or Header  |  1991-02-06  |  20KB  |  646 lines

  1. /*
  2.  * Written by Douglas Thomson (1989/1990)
  3.  *
  4.  * This source code is released into the public domain.
  5.  */
  6.  
  7. /*
  8.  * Name:    hardware independent screen IO module
  9.  * Purpose: This file contains the code to interface the rest of the
  10.  *           editor to the display and input hardware.
  11.  * File:    hwind.c
  12.  * Author:  Douglas Thomson
  13.  * System:  this file is intended to be system-independent
  14.  * Date:    October 2, 1989
  15.  * Notes:   This is the only module that is allowed to call the hardware
  16.  *           dependent display IO library.
  17.  *          Typically, functions here check whether any action is
  18.  *           necessary (for example, the cursor may already happen to be
  19.  *           in the required position), call hardware dependent functions
  20.  *           to achieve the required effect, and finally update status
  21.  *           information about the current state of the terminal display.
  22.  *          The idea behind this approach is to keep the hardware
  23.  *           dependent code as small and simple as possible, thus making
  24.  *           porting the code easier.
  25.  */
  26.  
  27. #ifdef HPXL
  28. #include "commonh"
  29. #include "hwdeph"
  30. #else
  31. #include "common.h"
  32. #include "hwdep.h"
  33. #endif
  34. #include <string.h>
  35.  
  36. /*
  37.  * prototypes for all functions in this file
  38.  */
  39. void xygoto ARGS((int col, int line));
  40. void set_attr ARGS((char attr));
  41. int c_insert ARGS((void));
  42. int c_delete ARGS((void));
  43. int eol_clear ARGS((void));
  44. int c_avail ARGS((void));
  45. int c_input ARGS((void));
  46. void c_uninput ARGS((char c));
  47. void c_output ARGS((int c));
  48. void s_output ARGS((char *s));
  49. void force_blank ARGS((void));
  50. void initialize ARGS((void));
  51. void terminate ARGS((void));
  52. void line_del ARGS((int line));
  53. void line_ins ARGS((int ins_line));
  54. void window_scroll_up ARGS((int top, int bottom));
  55. void window_scroll_down ARGS((int top, int bottom));
  56.  
  57. /*
  58.  * Name:    xygoto
  59.  * Purpose: To move the cursor to the required column and line.
  60.  * Date:    October 2, 1989
  61.  * Passed:  col:    desired column (0 up to max)
  62.  *          line:   desired line (0 up to max)
  63.  * Notes:   This function makes some attempt to use shorter movement
  64.  *           commands for simple movements (initially, only backspace
  65.  *           to move left one space).
  66.  */
  67. void xygoto(col, line)
  68. int col;
  69. int line;
  70. {
  71.     int diff;  /* how far backwards the cursor must be moved */
  72.  
  73.     /*
  74.      * If the cursor is on the right line, then a simpler movement
  75.      *  may be possible.
  76.      */
  77.     if (g_display.line == line) {
  78.         if ((diff = g_display.col - col) == 0) {
  79.             /*
  80.              * the cursor was in exactly the right spot, so no
  81.              *  action required.
  82.              */
  83.             return;
  84.         }
  85.         else if (diff == 1) {
  86.             /*
  87.              * the cursor only needs to move one space left, so try
  88.              *  simply backspacing (if the hardware supports it)
  89.              */
  90.             if (hw_backspace()) {
  91.                 g_display.col = col;
  92.                 return;
  93.             }
  94.         }
  95.     }
  96.  
  97.     /*
  98.      * use a full cursor addressing command. The hardware is required
  99.      *  to provide such a command, so there is no need to check.
  100.      */
  101.     g_display.col = col;
  102.     g_display.line = line;
  103.     hw_xygoto();
  104. }
  105.  
  106. /*
  107.  * Name:    set_attr
  108.  * Purpose: To record the attribute to be used for the next character
  109.  *           output.
  110.  * Date:    October 2, 1989
  111.  * Passed:  attr:              desired new attribute
  112.  * Returns: [g_status.wanted]: attribute to use next
  113.  * Notes:   Since other hardware commands can need to fiddle with the
  114.  *           attribute, it is better not to bother actually outputting
  115.  *           the hardware attribute command. This is done immediately
  116.  *           prior to sending the actual character.
  117.  */
  118. void set_attr(attr)
  119. char attr;
  120. {
  121.     g_status.wanted = attr;
  122. }
  123.  
  124. /*
  125.  * Name:    c_insert
  126.  * Purpose: To insert space for one character at the cursor position.
  127.  * Date:    October 2, 1989
  128.  * Notes:   If this function is available in the hardware, then it must
  129.  *           leave the cursor in its original position (or else
  130.  *           explicitly undefined [line = col = -1]) and insert one
  131.  *           character in front of the character that used to be under
  132.  *           the cursor.
  133.  *          No assumption is made about what the attribute of the inserted
  134.  *           character will be!
  135.  */
  136. int c_insert()
  137. {
  138.     int col;        /* used to copy characters along */
  139.     int old_col;    /* to remember current column */
  140.     int old_line;   /* to remember current line */
  141.  
  142.     /*
  143.      * It is permissible for hardware functions to leave the current
  144.      *  cursor position undefined (-1, -1). Hence we need to store the
  145.      *  current location for use later.
  146.      */
  147.     old_col = g_display.col;
  148.     old_line = g_display.line;
  149.  
  150.     if (hw_c_insert()) {
  151.         /*
  152.          * update memory version of screen
  153.          */
  154.         for (col=g_display.ncols-1; col > old_col; col--) {
  155.             g_screen[old_line][col] =
  156.                     g_screen[old_line][col-1];
  157.         }
  158.         g_screen[old_line][old_col].c = ' ';
  159.         g_screen[old_line][old_col].attr = 0xFF;
  160.         return TRUE;
  161.     }
  162.     return FALSE;
  163. }
  164.  
  165. /*
  166.  * Name:    c_delete
  167.  * Purpose: To delete the character under the cursor.
  168.  * Date:    October 10, 1989
  169.  * Notes:   If this function is available in the hardware, then it must
  170.  *           leave the cursor in its original position (or else
  171.  *           explicitly undefined [line = col = -1]) and delete the
  172.  *           character under the cursor.
  173.  *          The character which appears at the end of the line after the
  174.  *           delete is assumed to be a space with the normal attribute.
  175.  */
  176. int c_delete()
  177. {
  178.     int col;        /* used to copy characters along */
  179.     int old_col;    /* to remember current column */
  180.     int old_line;   /* to remember current line */
  181.  
  182.     /*
  183.      * It is permissible for hardware functions to leave the current
  184.      *  cursor position undefined (-1, -1). Hence we need to store the
  185.      *  current location for use later.
  186.      */
  187.     old_col = g_display.col;
  188.     old_line = g_display.line;
  189.  
  190.     if (hw_c_delete()) {
  191.         /*
  192.          * update memory version of screen
  193.          */
  194.         for (col=old_col; col < g_display.ncols-1; col++) {
  195.             g_screen[old_line][col] =
  196.                     g_screen[old_line][col+1];
  197.         }
  198.         g_screen[old_line][g_display.ncols-1].c = ' ';
  199.         g_screen[old_line][g_display.ncols-1].attr = g_display.normal;
  200.         return TRUE;
  201.     }
  202.     return FALSE;
  203. }
  204.  
  205. /*
  206.  * Name:    eol_clear
  207.  * Purpose: To clear the current line from the cursor to the end of the
  208.  *           line to normal spaces.
  209.  * Date:    October 2, 1989
  210.  * Notes:   If this function is available in the hardware, then it must
  211.  *           clear all the rest of the line to spaces, all with the normal
  212.  *           attribute, and leave the cursor exactly where it was (or else
  213.  *           explicitly undefined [line = col = -1]).
  214.  */
  215. int eol_clear()
  216. {
  217.     int col;
  218.     int old_col;    /* to remember current column */
  219.     int old_line;   /* to remember current line */
  220.  
  221.     old_col = g_display.col;
  222.     old_line = g_display.line;
  223.  
  224.     if (!hw_clreol()) {
  225.         return FALSE;
  226.     }
  227.     for (col=old_col; col < g_display.ncols; col++) {
  228.         g_screen[old_line][col].c = ' ';
  229.         g_screen[old_line][col].attr = g_display.normal;
  230.     }
  231.     return TRUE;
  232. }
  233.  
  234. /*
  235.  * Name:    c_avail
  236.  * Purpose: To test whether or not there is a character available to be
  237.  *           read from the user.
  238.  * Date:    October 2, 1989
  239.  * Notes:   Under some circumstances it is convenient to be able to push
  240.  *           a few characters back into the input stream, making it appear
  241.  *           to the rest of the editor that the user typed something
  242.  *           different (for example, the tab key might be turning into
  243.  *           the required number of spaces).
  244.  */
  245. int c_avail()
  246. {
  247.     if (g_status.ungotcount) {
  248.         return TRUE;
  249.     }
  250.     return hw_c_avail();
  251. }
  252.  
  253. /*
  254.  * Name:    c_input
  255.  * Purpose: To input the next character typed by the user.
  256.  * Date:    October 2, 1989
  257.  * Notes:   Under some circumstances it is convenient to be able to push
  258.  *           a few characters back into the input stream, making it appear
  259.  *           to the rest of the editor that the user typed something
  260.  *           different (for example, the tab key might be turning into
  261.  *           the required number of spaces).
  262.  */
  263. int c_input()
  264. {
  265.     if (g_status.ungotcount) {
  266.         return g_status.ungotbuff[--g_status.ungotcount];
  267.     }
  268.     return hw_c_input();
  269. }
  270.  
  271. /*
  272.  * Name:    c_uninput
  273.  * Purpose: To push a character back into the input stream, so that it
  274.  *           will be inputted next time c_input is called.
  275.  * Date:    October 2, 1989
  276.  * Notes:   No check is made to see if the buffer has overflowed, so
  277.  *           beware when using this one!
  278.  */
  279. void c_uninput(c)
  280. char c;
  281. {
  282.     g_status.ungotbuff[g_status.ungotcount++] = c;
  283. }
  284.  
  285. /*
  286.  * Name:    c_output
  287.  * Purpose: To output a single character at the cursor position, and then
  288.  *           advance the cursor.
  289.  * Date:    October 2, 1989
  290.  * Passed:  c: character to be output
  291.  * Notes:   The character is only outputted if it would be on the screen.
  292.  *          The cursor position should not be relied upon after writing
  293.  *           the rightmost column.
  294.  *          It is left up to the hardware to deal with the bottom right
  295.  *           corner of the screen! This is against the philosophy of
  296.  *           keeping the hardware dependent part simple, but we want to
  297.  *           be able to take advantage of any hardware that can do a
  298.  *           decent job of this character.
  299.  */
  300. void c_output(c)
  301. int c;
  302. {
  303.     if (g_display.col < g_display.ncols) {
  304.         g_screen[g_display.line][g_display.col].c = c;
  305.         g_screen[g_display.line][g_display.col].attr =
  306.                 g_status.wanted;
  307.         hw_c_output(c);
  308.  
  309.         /*
  310.          * check that cursor position is still known...
  311.          */
  312.         if (g_display.col != -1) {
  313.             ++g_display.col;
  314.         }
  315.     }
  316. }
  317.  
  318. /*
  319.  * Name:    s_output
  320.  * Purpose: To output character string at the cursor position, advancing
  321.  *           the cursor by the length of the string.
  322.  * Date:    October 2, 1989
  323.  * Passed:  s: string to output
  324.  * Notes:   At present, this function is rarely used, so the simple
  325.  *           approach of calling the character output routine is quite
  326.  *           acceptable. Maybe someday the entire string could be output
  327.  *           with a single system call?
  328.  */
  329. void s_output(s)
  330. char *s;
  331. {
  332.     while (*s) {
  333.         c_output(*s++);
  334.     }
  335. }
  336.  
  337. /*
  338.  * Name:    force_blank
  339.  * Purpose: To set the status of the screen so that nothing can appear to
  340.  *           be what it needs to be, so that the entire screen will be
  341.  *           redrawn.
  342.  * Date:    October 2, 1989
  343.  * Notes:   This could be done more efficiently with a clear screen
  344.  *           terminal command in the hardware dependent module, but it
  345.  *           does not seem worthwhile to add the extra function when
  346.  *           this is the only time clear screen would be used.
  347.  */
  348. void force_blank()
  349. {
  350.     int line;
  351.     int col;
  352.  
  353.     for (line=0; line < g_display.nlines; line++) {
  354.         for (col=0; col < g_display.ncols; col++) {
  355.             g_screen[line][col].c = 0xFF;
  356.             g_screen[line][col].attr = 0x00;
  357.         }
  358.     }
  359. }
  360.  
  361. /*
  362.  * Name:    initialize
  363.  * Purpose: To initialize all the screen status info that is not hardware
  364.  *           dependent, and call the hardware initialization routine to
  365.  *           pick up the hardware dependent stuff.
  366.  * Date:    October 2, 1989
  367.  * Returns: [g_status and g_display]: all set up ready to go
  368.  * Notes:   It is assumed that g_status and g_display are all \0's to begin
  369.  *           with (the default if they use static storage). If this may
  370.  *           not be the case, then clear them explicitly here.
  371.  */
  372. void initialize()
  373. {
  374.     /*
  375.      * we do not know where the cursor is yet
  376.      */
  377.     g_display.col = -1;
  378.     g_display.line = -1;
  379.  
  380.     /*
  381.      * do the hardware initialization first, since this allocates the main
  382.      *  text buffer and sets up other info needed here later.
  383.      */
  384.     hw_initialize();
  385.  
  386.     /*
  387.      * the main text buffer must be preceded by a \0, so that backward
  388.      *  searches can see the start of the string
  389.      */
  390.     *g_status.start_mem++ = '\0';
  391.  
  392.     /*
  393.      * most of the system's text pointers are safer set to the start
  394.      *  of the text buffer - some of these may not be strictly
  395.      *  necessary.
  396.      */
  397.     g_status.temp_end = g_status.start_mem;
  398.     g_status.end_mem = g_status.start_mem;
  399.  
  400.     /*
  401.      * set the default modes - may want to read this from a file later
  402.      */
  403.     g_status.insert = TRUE;
  404.     g_status.indent = TRUE;
  405.     g_status.unindent = TRUE;
  406.  
  407.     /*
  408.      * set default interval between tabs
  409.      */
  410.     g_status.tab_size = 4;
  411.  
  412.     /*
  413.      * set the number of lines from one page that should still be visible
  414.      *  on the next page after page up or page down.
  415.      */
  416.     g_status.overlap = 1;
  417.  
  418.     /*
  419.      * set the time in seconds between auto-saves
  420.      */
  421.     g_status.save_interval = 300;
  422.  
  423.     /*
  424.      * initially, text should use the normal attribute
  425.      */
  426.     g_status.wanted = g_display.normal;
  427.  
  428.     /*
  429.      * record that we have no idea what is currently on the screen.
  430.      */
  431.     force_blank();
  432. }
  433.  
  434. /*
  435.  * Name:    terminate
  436.  * Purpose: To do any hardware independent housekeeping, and call the
  437.  *           hardware dependent code to clean up screen modes and leave
  438.  *           the cursor at the bottom of the screen in normal attribute.
  439.  * Date:    October 2, 1989
  440.  * Notes:   At present, there is nothing apart from hardware dependent
  441.  *           code required.
  442.  */
  443. void terminate()
  444. {
  445.     hw_terminate();
  446. }
  447.  
  448. /*
  449.  * Name:    line_del
  450.  * Purpose: To delete a given line on the screen.
  451.  * Date:    October 2, 1989
  452.  * Passed:  line:   line to be deleted
  453.  * Notes:   If the hardware does not support this one, then the editor
  454.  *           will be rather slow!
  455.  */
  456. void line_del(line)
  457. int line;
  458. {
  459.     screen_chars *p, *q;    /* used to shuffle screen copy */
  460.     int col;                /* counter for chars in each line */
  461.     screen_chars blank;     /* the blank/normal character */
  462.  
  463.     if (!hw_linedel(line)) {
  464.         return;
  465.     }
  466.  
  467.     /*
  468.      * copy text to close the gap
  469.      */
  470.     while (line < g_display.nlines-1) {
  471.         p = g_screen[line];
  472.         q = g_screen[line+1];
  473.         for (col=g_display.ncols; col > 0; col--) {
  474.             *p++ = *q++;  /* all C compilers support structure assignments? */
  475.         }
  476.         ++line;
  477.     }
  478.  
  479.     /*
  480.      * now mark the bottom line as all blank
  481.      */
  482.     blank.c = ' ';
  483.     blank.attr = g_display.normal;
  484.     for (col=g_display.ncols-1; col >= 0; col--) {
  485.         g_screen[g_display.nlines-1][col] = blank;
  486.     }
  487. }
  488.  
  489. /*
  490.  * Name:    line_ins
  491.  * Purpose: To insert a given line on the screen. The cursor line will
  492.  *           move down, leaving the cursor on a new blank/normal line.
  493.  * Date:    October 2, 1989
  494.  * Passed:  ins_line: line to be inserted
  495.  * Notes:   If the hardware does not support this one, then the editor
  496.  *           will be rather slow!
  497.  */
  498. void line_ins(ins_line)
  499. int ins_line;
  500. {
  501.     int line;              /* line being moved */
  502.     int col;               /* column being moved */
  503.     screen_chars *p, *q;   /* dest and source of move */
  504.     screen_chars blank;    /* blank/normal character */
  505.  
  506.     if (!hw_lineins(ins_line)) {
  507.         return;
  508.     }
  509.  
  510.     /*
  511.      * shuffle status screen to make a gap
  512.      */
  513.     for (line=g_display.nlines-1; line > ins_line; line--) {
  514.         p = g_screen[line];
  515.         q = g_screen[line-1];
  516.         for (col=g_display.ncols; col > 0; col--) {
  517.             *p++ = *q++;
  518.         }
  519.     }
  520.  
  521.     /*
  522.      * set the new inserted line to blank/normal
  523.      */
  524.     blank.c = ' ';
  525.     blank.attr = g_display.normal;
  526.     for (col=g_display.ncols-1; col >= 0; col--) {
  527.         g_screen[ins_line][col] = blank;
  528.     }
  529. }
  530.  
  531. /*
  532.  * Name:    window_scroll_up
  533.  * Purpose: To scroll all the lines between top and bottom up one line.
  534.  * Date:    October 10, 1989
  535.  * Passed:  top:    top line to be scrolled
  536.  *          bottom: bottom line to be scrolled
  537.  * Notes:   If the hardware supports windows, then this is likely to look
  538.  *           better than inserting and deleting lines.
  539.  */
  540. void window_scroll_up(top, bottom)
  541. int top;
  542. int bottom;
  543. {
  544.     int line;              /* line being moved */
  545.     int col;               /* column being moved */
  546.     screen_chars *p, *q;   /* dest and source of move */
  547.     screen_chars blank;    /* blank/normal character */
  548.  
  549.     if (hw_scroll_up(top, bottom)) {
  550.         /*
  551.          * copy text to close the gap
  552.          */
  553.         line = top;
  554.         while (line < bottom) {
  555.             p = g_screen[line];
  556.             q = g_screen[line+1];
  557.             for (col=g_display.ncols; col > 0; col--) {
  558.                 *p++ = *q++;
  559.             }
  560.             ++line;
  561.         }
  562.  
  563.         /*
  564.          * now mark the bottom line as all blank
  565.          */
  566.         blank.c = ' ';
  567.         blank.attr = g_display.normal;
  568.         for (col=g_display.ncols-1; col >= 0; col--) {
  569.             g_screen[bottom][col] = blank;
  570.         }
  571.     }
  572.     else {
  573.         /*
  574.          * no hardware windows, so do it with insert and delete line
  575.          */
  576.         line_del(top);
  577.         if (bottom < g_display.nlines-1) {
  578.             line_ins(bottom);
  579.         }
  580.     }
  581. }
  582.  
  583. /*
  584.  * Name:    window_scroll_down
  585.  * Purpose: To scroll all the lines between top and bottom down one line.
  586.  * Date:    October 10, 1989
  587.  * Passed:  top:    top line to be scrolled
  588.  *          bottom: bottom line to be scrolled
  589.  * Notes:   If the hardware supports windows, then this is likely to look
  590.  *           better than inserting and deleting lines.
  591.  */
  592. void window_scroll_down(top, bottom)
  593. int top;
  594. int bottom;
  595. {
  596.     int line;              /* line being moved */
  597.     int col;               /* column being moved */
  598.     screen_chars *p, *q;   /* dest and source of move */
  599.     screen_chars blank;    /* blank/normal character */
  600.  
  601.     if (hw_scroll_down(top, bottom)) {
  602.         /*
  603.          * shuffle status screen to make a gap
  604.          */
  605.         for (line=bottom; line > top; line--) {
  606.             p = g_screen[line];
  607.             q = g_screen[line-1];
  608.             for (col=g_display.ncols; col > 0; col--) {
  609.                 *p++ = *q++;
  610.             }
  611.         }
  612.  
  613.         /*
  614.          * set the new inserted line to blank/normal
  615.          */
  616.         blank.c = ' ';
  617.         blank.attr = g_display.normal;
  618.         for (col=g_display.ncols-1; col >= 0; col--) {
  619.             g_screen[top][col] = blank;
  620.         }
  621.     }
  622.     else {
  623.         /*
  624.          * no hardware windows, so do it with insert and delete line
  625.          */
  626.         if (bottom < g_display.nlines-1) {
  627.             line_del(bottom);
  628.         }
  629.         line_ins(top);
  630.     }
  631. }
  632.  
  633. /*
  634.  * Name:    os_shell
  635.  * Purpose: To shell out of the editor into the operating system, in such a
  636.  *           way that editing may be resumed later.
  637.  * Date:    November 28, 1990
  638.  */
  639. void os_shell()
  640. {
  641.     xygoto(0, g_display.nlines-1);
  642.     if (hw_os_shell()) {
  643.         force_blank();   /* get the screen fixed if necessary */
  644.     }
  645. }
  646.